#include <SPI.h>

// -------------------------- 1. 硬件引脚定义 --------------------------
// NRF24L01引脚（与之前发送代码一致）
#define CE_PIN    9    // CE接Arduino D9
#define CSN_PIN   10   // CSN接Arduino D10
// 摇杆引脚（按你的定义）
const int joy1_X = A2;  // 摇杆1 X轴（备用，当前未使用）A2
const int joy1_Y = A1;  // 摇杆1 Y轴（备用，当前未使用）A1
const int joy2_X = A5;  // 摇杆2 X轴（控制左右转向） A5
const int joy2_Y = A4;  // 摇杆2 Y轴（控制前后移动）A4

// -------------------------- 2. 小车控制命令定义 --------------------------
// 你指定的2字节控制指令
const uint8_t car_stop[2] = {0xf2, 0xf1};  // 小车停止
const uint8_t car_q[2] = {0xf2, 0xf2};     // 小车前进
const uint8_t car_t[2] = {0xf2, 0xf3};     // 小车后退
const uint8_t car_z[2] = {0xf2, 0xf4};     // 小车左转
const uint8_t car_y[2] = {0xf2, 0xf5};     // 小车右转

// -------------------------- 3. NRF24L01配置参数 --------------------------
#define RF_CHANNEL      0x0A                // 射频通道10（收发必须一致）
#define PAYLOAD_WIDTH   2                   // 数据长度2字节（与控制命令匹配）
const uint8_t DEVICE_ADDR[5] = {0x11, 0x22, 0x33, 0x44, 0x55};  // 设备地址（收发必须一致）

// -------------------------- 4. NRF24L01寄存器与命令定义 --------------------------
// 寄存器地址
const uint8_t REG_CONFIG      = 0x00;  // 配置寄存器
const uint8_t REG_EN_AA       = 0x01;  // 自动应答使能
const uint8_t REG_EN_RXADDR   = 0x02;  // 接收地址使能
const uint8_t REG_SETUP_AW    = 0x03;  // 地址宽度设置
const uint8_t REG_SETUP_RETR  = 0x04;  // 自动重发设置
const uint8_t REG_RF_CH       = 0x05;  // RF频道
const uint8_t REG_RF_SETUP    = 0x06;  // RF设置
const uint8_t REG_STATUS      = 0x07;  // 状态寄存器
const uint8_t REG_RX_ADDR_P0  = 0x0A;  // 接收地址0（5字节）
const uint8_t REG_TX_ADDR     = 0x10;  // 发送地址（5字节）
const uint8_t REG_RX_PW_P0    = 0x11;  // 接收管道0数据宽度
const uint8_t REG_FEATURE     = 0x1D;  // 功能寄存器
const uint8_t REG_DYNPD       = 0x1C;  // 动态负载配置
// 命令
const uint8_t CMD_R_REGISTER   = 0x00; // 读寄存器命令
const uint8_t CMD_W_REGISTER   = 0x20; // 写寄存器命令
const uint8_t CMD_W_TX_PAYLOAD = 0xA0; // 写发送数据命令
const uint8_t CMD_FLUSH_TX     = 0xE1; // 清空发送FIFO命令
const uint8_t CMD_NOP          = 0xFF; // 空操作（读状态用）

// -------------------------- 5. 全局变量 --------------------------
uint8_t current_cmd[2];  // 当前要发送的控制命令（默认初始化为停止）
unsigned int send_count = 0;  // 发送次数计数器（unsigned int支持0~65535计数）

void setup() {
  // 初始化串口（用于调试摇杆值和发送状态）
  Serial.begin(9600);
  // 初始化摇杆引脚（模拟输入无需额外配置，analogRead自动识别）
  pinMode(joy2_X, INPUT);
  pinMode(joy2_Y, INPUT);
  
  // 初始化NRF24L01并配置为发送模式
  if (!nrf24l01_init()) {
    Serial.println("❌ NRF24L01初始化失败！");
    while (1); // 初始化失败则卡住，提示检查硬件
  }
  Serial.println("✅ NRF24L01发送模式就绪");
  Serial.println("📌 摇杆2控制逻辑：Y>950前进 | Y<100后退 | X>950右转 | X<100左转 | 其他停止");
  Serial.println("📌 发送次数统计：每次发送（成功/失败）均累计次数\n");
  
  // 初始命令设为“停止”
  memcpy(current_cmd, car_stop, PAYLOAD_WIDTH);
}

void loop() {
  // -------------------------- 步骤1：读取摇杆2的X/Y轴值 --------------------------
  int joy2_Y_val = analogRead(joy2_Y);  // 读取摇杆2 Y轴（前后控制）
  int joy2_X_val = analogRead(joy2_X);  // 读取摇杆2 X轴（左右控制）

  // -------------------------- 步骤2：根据摇杆值判断控制命令 --------------------------
  // 优先级：前后（Y轴）高于左右（X轴），避免冲突（如同时前进+左转，优先前进）
  if (joy2_Y_val > 950) {
    // Y轴大于950 → 前进
    memcpy(current_cmd, car_q, PAYLOAD_WIDTH);
  } else if (joy2_Y_val < 100) {
    // Y轴小于100 → 后退
    memcpy(current_cmd, car_t, PAYLOAD_WIDTH);
  } else if (joy2_X_val > 950) {
    // X轴大于950 → 右转（Y轴无操作时生效）
    memcpy(current_cmd, car_z, PAYLOAD_WIDTH);
  } else if (joy2_X_val < 100) {
    // X轴小于100 → 左转（Y轴无操作时生效）
        memcpy(current_cmd, car_y, PAYLOAD_WIDTH);
  } else {
    // 所有轴无有效操作 → 停止
    memcpy(current_cmd, car_stop, PAYLOAD_WIDTH);
  }

  // -------------------------- 步骤3：发送控制命令 + 统计发送次数 --------------------------
  bool send_ok = nrf24l01_send(current_cmd, PAYLOAD_WIDTH);
  send_count++;  // 关键：每发送一次（无论成功/失败），次数+1

  // -------------------------- 步骤4：串口打印调试信息（含发送次数） --------------------------
  Serial.print("【累计发送次数：");
  Serial.print(send_count);  // 打印当前累计发送次数
  Serial.print("】 | 摇杆2：Y=");
  Serial.print(joy2_Y_val);
  Serial.print(" | X=");
  Serial.print(joy2_X_val);
  Serial.print(" | 发送命令：0x");
  Serial.print(current_cmd[0], HEX);
  Serial.print(" 0x");
  Serial.print(current_cmd[1], HEX);
  Serial.print(" | 发送状态：");
  Serial.println(send_ok ? "成功" : "失败");

  // 控制发送频率（与摇杆操作响应速度匹配，500ms一次）
  delay(500);
}

// -------------------------- NRF24L01底层函数（无修改） --------------------------
// 初始化NRF24L01（包含射频配置和发送模式设置）
bool nrf24l01_init() {
  // 初始化NRF24L01引脚
  pinMode(CE_PIN, OUTPUT);
  pinMode(CSN_PIN, OUTPUT);
  digitalWrite(CSN_PIN, HIGH); // 初始不选通模块
  digitalWrite(CE_PIN, LOW);   // 初始CE低电平（待机模式）
  SPI.begin();                 // 初始化SPI总线
  delay(100);                  // 等待模块上电稳定

  // 检查模块连接（读取配置寄存器，未连接时返回0xFF）
  if (read_nrf_register(REG_CONFIG) == 0xFF) {
    return false;
  }

  // 配置射频参数（通道、功率、速率等）
  if (!nrf24l01_config_rf()) {
    return false;
  }

  // 配置为发送模式
  nrf24l01_set_tx_mode();

  return true;
}

// 配置NRF24L01射频参数（与接收端一致）
bool nrf24l01_config_rf() {
  // 地址宽度：5字节
  write_nrf_register(REG_SETUP_AW, 0x03);
  // 重发配置：500us延迟，10次重试（提高可靠性）
  write_nrf_register(REG_SETUP_RETR, 0x1A);
  // 射频通道：0x0A（与定义一致）
  write_nrf_register(REG_RF_CH, RF_CHANNEL);
  // 射频功率：0dBm（最大），速率：2Mbps
  write_nrf_register(REG_RF_SETUP, 0x0F);
  // 接收管道0数据宽度：2字节（与命令长度匹配）
  write_nrf_register(REG_RX_PW_P0, PAYLOAD_WIDTH);
  // 设置接收地址（用于自动应答）和发送地址
  write_nrf_address(REG_RX_ADDR_P0, DEVICE_ADDR, 5);
  write_nrf_address(REG_TX_ADDR, DEVICE_ADDR, 5);

  return true;
}

// 设置NRF24L01为发送模式（匹配你之前的初始化逻辑）
void nrf24l01_set_tx_mode() {
  // 清空发送FIFO，避免残留数据
  digitalWrite(CSN_PIN, LOW);
  SPI.transfer(CMD_FLUSH_TX);
  digitalWrite(CSN_PIN, HIGH);
  delayMicroseconds(10);

  // 配置CONFIG寄存器：PRIM_RX=0（发送模式），PWR_UP=1（上电），16位CRC
  uint8_t config = read_nrf_register(REG_CONFIG);
  config = (config & 0xF9) | 0x02; // 确保PRIM_RX=0、PWR_UP=1
  write_nrf_register(REG_CONFIG, config);

  // 仅启用管道0自动应答（与接收端匹配）
  write_nrf_register(REG_EN_AA, 0x01);
  write_nrf_register(REG_EN_RXADDR, 0x01); // 使能管道0

  // 启用动态负载和ACK负载（与你之前的配置一致）
  write_nrf_register(REG_FEATURE, 0x06);
  write_nrf_register(REG_DYNPD, 0x01); // 管道0开启动态负载

  // 等待PLL时钟稳定（关键延时，避免发送不稳定）
  digitalWrite(CE_PIN, LOW);
  delay(150);

  // 清除所有中断标志（避免残留状态影响发送）
  write_nrf_register(REG_STATUS, 0x70);
}

// 读取NRF24L01单个寄存器
uint8_t read_nrf_register(uint8_t reg_addr) {
  uint8_t cmd = CMD_R_REGISTER | (reg_addr & 0x1F); // 读命令（5位地址）
  digitalWrite(CSN_PIN, LOW);
  SPI.transfer(cmd);                  // 发送读命令
  uint8_t val = SPI.transfer(CMD_NOP); // 读取寄存器值（发空字节）
  digitalWrite(CSN_PIN, HIGH);
  return val;
}

// 写入NRF24L01单个寄存器
void write_nrf_register(uint8_t reg_addr, uint8_t value) {
  uint8_t cmd = CMD_W_REGISTER | (reg_addr & 0x1F); // 写命令（5位地址）
  digitalWrite(CSN_PIN, LOW);
  SPI.transfer(cmd);                  // 发送写命令
  SPI.transfer(value);                // 写入寄存器值
  digitalWrite(CSN_PIN, HIGH);
  delayMicroseconds(10); // 确保数据写入完成
}

// 写入NRF24L01多字节寄存器（用于地址配置）
void write_nrf_address(uint8_t reg_addr, const uint8_t* data, uint8_t len) {
  uint8_t cmd = CMD_W_REGISTER | (reg_addr & 0x1F);
  digitalWrite(CSN_PIN, LOW);
  SPI.transfer(cmd);
  for (int i = 0; i < len; i++) {
    SPI.transfer(data[i]);
    delayMicroseconds(1);
  }
  digitalWrite(CSN_PIN, HIGH);
  delayMicroseconds(10);
}

// 发送数据（返回发送结果：true成功，false失败）
bool nrf24l01_send(const uint8_t* data, uint8_t len) {
  // 检查数据长度（避免超过设置的负载宽度）
  if (len > PAYLOAD_WIDTH) return false;

  // 清除之前的状态标志（防止残留标志影响判断）
  write_nrf_register(REG_STATUS, 0x70);

  // 写入发送数据到TX FIFO
  digitalWrite(CSN_PIN, LOW);
  SPI.transfer(CMD_W_TX_PAYLOAD); // 发送“写TX数据”命令
  for (int i = 0; i < len; i++) {
    SPI.transfer(data[i]);        // 写入控制命令
  }
  digitalWrite(CSN_PIN, HIGH);
  delayMicroseconds(10);

  // 启动发送（CE高电平至少10us，确保模块触发发送）
  digitalWrite(CE_PIN, HIGH);
  delayMicroseconds(15);
  digitalWrite(CE_PIN, LOW);

  // 等待发送结果（超时时间200ms，匹配重发配置）
  uint32_t timeout = millis();
  while (millis() - timeout < 200) {
    uint8_t status = read_nrf_register(REG_STATUS);

    if (status & (1 << 5)) { // TX_DS位（第5位）置1 → 发送成功且收到应答
      write_nrf_register(REG_STATUS, (1 << 5)); // 清除标志
      return true;
    }

    if (status & (1 << 4)) { // MAX_RT位（第4位）置1 → 重发超时失败
      write_nrf_register(REG_STATUS, (1 << 4)); // 清除标志
      flush_tx_fifo();                          // 清空TX FIFO，避免堵塞
      return false;
    }

    delayMicroseconds(200); // 降低轮询频率，减少CPU占用
  }

  // 超时处理（清空FIFO，防止下次发送异常）
  flush_tx_fifo();
  return false;
}

// 清空NRF24L01的TX FIFO（发送失败时调用）
void flush_tx_fifo() {
  digitalWrite(CSN_PIN, LOW);
  SPI.transfer(CMD_FLUSH_TX);
  digitalWrite(CSN_PIN, HIGH);
  delayMicroseconds(10);
}